package com.cyw.common.utils;

import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.cyw.common.utils.BaseUtils.isAnyNullThr;

/**
 * 脱敏「马赛克」工具类
 * @Author: cyw
 * @CreateTime: 2021/4/1 17:35
 */
public class MosaicUtils {

    /**
     * 马赛克方法，仅保留输入的字符串的首尾，其余字符替换为 *
     * <p/>
     * 字符串长度小于等于 1 的情况下，不做任何操作
     * <p/>
     * 字符串长度等于 2 的情况下，仅保留首部
     * <p/>
     * 兼容 emoji 等 4 字节字符
     */
    public static String mosaic(String s) {
        if (s == null || s.length() <= 1) {
            return s;
        }

        int head = s.codePointAt(0);
        int headCharCount = Character.charCount(head);
        if (s.length() == 2) {
            if (headCharCount == 2) {
                return s;
            } else {
                return s.substring(0, 1) + "*";
            }
        }

        int tail = s.codePointAt(s.length() - 2);
        int tailCharCount = Character.charCount(tail);
        if (tailCharCount == 1) {
            tail = s.codePointAt(s.length() - 1);
        }

        // 4字节字符+普通字符
        if (s.length() == 3 && headCharCount == 2) {
            return s.substring(0, 2) + "*";
        }
        // 普通字符+4字节字符
        else if (s.length() == 3 && tailCharCount == 2) {
            return s.substring(0, 1) + "*";
        }
        // 4字节字符+4字节字符
        else if (s.length() == 4 && headCharCount == 2 && tailCharCount == 2) {
            return s.substring(0, 2) + "*";
        }

        int[] codePoints = new int[s.length()];
        int i = 0;
        // 首部
        codePoints[i++] = head;

        // 中间的*部
        for (int offset = headCharCount; offset < s.length() - tailCharCount; ) {
            // 42 即 *
            codePoints[i++] = 42;

            int codepoint = s.codePointAt(offset);
            offset += Character.charCount(codepoint);
        }
        // 尾部
        codePoints[i++] = tail;

        return new String(codePoints, 0, i);
    }

    /**
     * 脱敏
     * @param str           明文
     * @param keepHeadCount 保留头部明文位数
     * @param keepTailCount 保留尾部明文位数
     * @return 脱敏数据
     */
    public static String mosaic(String str, Integer keepHeadCount, Integer keepTailCount) {
        isAnyNullThr("非法请求参数", str, keepHeadCount, keepTailCount);

        if (str.length() < keepHeadCount + keepTailCount) {
            BaseUtils.thrBaseException("明文过短，无法脱敏");
        }

        int len = str.length() - keepHeadCount - keepTailCount;
        return len == 0 ? str :
                str.substring(0, keepHeadCount)
                        + Stream.generate(() -> "*").limit(len).collect(Collectors.joining())
                        + str.substring(str.length() - keepTailCount);
    }

    public static void main(String[] args) {
        System.out.println(mosaic("123456"));
        System.out.println(mosaic("15988888888", 3, 3));
        System.out.println(mosaic("123456", 3, 3));

    }
}
